<template>
    <div class="virtual-content" ref="scroll" :style="{ height: height + 'px' }">
        <div class="virtual-list" :style="{ height: ((itemHeight + margin) * count) + 'px' }">
            <slot :topIndex="top" :bottomIndex="bottom"></slot>
        </div>
    </div>
</template>

<script>
import { debounce } from "lodash-es";
export default {
    name: 'VirtualComponent',
    props: {
        // offset指个数，上下偏移多少个开始渲染
        offset: {
            type: Number,
            default: 4
        },
        // 总数量
        count: {
            required: true,
            type: Number,
            default: 0
        },
        // 间距
        margin: {
            type: Number, 
            default: 0
        },
        // 总高度
        height: {
            required: true,
            type: Number,
            default: 0
        },
        // 单项高度
        itemHeight: { 
            required: true,
            type: Number,
            default: 0
        }
    },
    data() {
        return {
            top : 0, // 渲染起点index
            bottom: 0, // 渲染结尾index
            firstBottom: 0, // 渲染初使长度
        }
    },
    created() {
        this.initButtomIndex()
        this.debounceScroll = debounce(this.scrollEvent, 16, {
            trailing: true
        })
    },
    mounted() {
        this.initScroll()
    },
    methods: {
        // 初始化渲染列表数量
        initButtomIndex() {
            let index = this.height / (this.margin + this.itemHeight)
            let bottomIndex = Math.ceil(index)
            this.bottom = bottomIndex + this.offset
            this.firstBottom = bottomIndex + this.offset
        },
        // 监听滚动
        initScroll() {
            this.scrollDom = this.$refs['scroll']
            this.scrollDom .addEventListener('scroll', this.debounceScroll, {
                passive: true
            })
        },
        scrollEvent (e) {
            let scrollTop = e.target.scrollTop
            let scrollItem = this.itemHeight + this.margin
            if(scrollTop >= scrollItem) {
                let scrollIndex =  Math.ceil(scrollTop / scrollItem)
                let offset = this.offset
                this.top = scrollIndex >= offset ? scrollIndex - offset : 0
                this.bottom = scrollIndex + this.firstBottom
                scrollIndex = null
                offset = null
            } else {
                this.top = 0
                this.bottom = this.firstBottom
            }
            scrollTop = null
            scrollItem = null
        }
    },
    beforeDestory() {
        if(this.scrollDom) {
            this.scrollDom.removeEventListener('scroll', this.debounceScroll, {
                passive: true
            })
            this.scrollDom = null
            this.debounceScroll = null
        }
    }
}
</script>

<style lang="less" scoped>
    .virtual-content {
        width: 100%;
        height: 100%;
        overflow-y: auto;
        .virtual-list {
            position: relative;
            /deep/ .virtual-scroll-item {
                position: absolute;
            }
        }
    }
</style>